package com.framework.context.support;

import com.framework.beans.BeanDefinition;
import com.framework.beans.MutablePropertyValues;
import com.framework.beans.PropertyValue;
import com.framework.beans.factory.support.BeanDefinitionRegistry;
import com.framework.beans.factory.xml.XmlBeanDefinitionReader;
import com.framework.utils.SpringUtils;

import java.lang.reflect.Method;

// Ioc容器具体实现类
public class ClassPathXmlApplicationContext extends AbstractApplicationContext {

    public ClassPathXmlApplicationContext(String configLocation) {
        this.configLocation = configLocation;
        beanDefinitionReader = new XmlBeanDefinitionReader();
        try {
            this.refresh();
        } catch (Exception e) {
        }
    }

    // 按Name获取Bean
    @Override
    public Object getBean(String name) throws Exception {
        // 容器存在直接获取
        Object o = singletonObjects.get(name);
        if (o != null) return o;
        // 获取注册表
        BeanDefinitionRegistry registry = beanDefinitionReader.getRegistry();
        // 获取 Bean信息
        BeanDefinition beanDefinition = registry.getBeanDefinition(name);
        if (beanDefinition == null) {
            return null;
        }
        // 拿到全限定名类 , 并创建对象
        String className = beanDefinition.getClassName();
        Class<?> clazz = Class.forName(className);
        Object beanObj = clazz.newInstance();

        // 遍历 property标签
        MutablePropertyValues propertyValues = beanDefinition.getPropertyValues();
        for (PropertyValue propertyValue : propertyValues) {
            String propertyName = propertyValue.getName();
            String value = propertyValue.getValue();
            String ref = propertyValue.getRef();
            String methodName = SpringUtils.getSetterMethodFieldName(propertyName);
            if (ref != null && !"".equals(ref)) {
                for (Method method : clazz.getMethods()) {
                    if (method.getName().equals(methodName)) {
                        // set注入
                        method.invoke(beanObj, getBean(ref));
                    }
                }
            }
            if (value != null && !"".equals(value)) {
                Method method = clazz.getMethod(methodName, String.class);
                method.invoke(beanObj, value);
            }
        }

        singletonObjects.put(name, beanObj);
        return beanObj;
    }

    @Override
    public <T> T getBean(String name, Class<? extends T> clazz) throws Exception {
        Object bean = getBean(name);
        if (bean != null) return clazz.cast(bean);
        return null;
    }
}
